package com.spring.framework.factory;

import com.spring.framework.bean.BeanDefinition;
import com.spring.framework.enums.SpringError;
import com.spring.framework.exception.SpringException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * bean工厂类，生产bean，存贮bean
 * @author XiaoHei
 * @date 2021/12/1 14:10
 */
public class BeanFactory {

    private final Logger log = LoggerFactory.getLogger(BeanFactory.class);

    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    public Object getBean(String beanName) {
        Object bean = singletonObjects.get(beanName);
        if (bean == null) {
            synchronized (singletonObjects) {
                if (bean == null && beanDefinitionMap.containsKey(beanName)) {
                    BeanDefinition bd = beanDefinitionMap.get(beanName);
                    Class<?> clazz = bd.getBeanClass();
                    try {
                        bean = clazz.newInstance();
                    } catch (InstantiationException | IllegalAccessException e) {
                        log.error("初始化bean发生错误", e);
                    }
                    if ("singleton".equals(bd.getScope())) {
                        singletonObjects.put(beanName, bean);
                    }
                }
            }
        }
        return bean;
    }

    public void registryBeanDefinition(String beanName, BeanDefinition bd) {
        beanDefinitionMap.putIfAbsent(beanName, bd);
    }

    public void initBean() {
        Set<Map.Entry<String, BeanDefinition>> entries = beanDefinitionMap.entrySet();
        for (Map.Entry<String, BeanDefinition> entry : entries) {
            BeanDefinition beanDefinition = entry.getValue();
            String scope = beanDefinition.getScope();
            if ("singleton".equals(scope)) {
                Class<?> beanClass = beanDefinition.getBeanClass();
                Object bean = null;
                try {
                    bean = beanClass.newInstance();
                } catch (InstantiationException | IllegalAccessException e) {
                    e.printStackTrace();
                }
                singletonObjects.put(beanDefinition.getBeanName(), bean);
            }
        }
        log.info("BeanFactory init completed");
    }
}
